package me.stone.stanimeclient.core.ui.adapters

import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.ViewDataBinding
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import me.stone.stanimeclient.core.common.extensions.dip
import me.stone.stanimeclient.core.model.FanSimpleItem
import me.stone.stanimeclient.core.ui.adapters.holder.ViewBindingWrapperHolder
import me.stone.stanimeclient.core.ui.adapters.listener.OnItemClickListener
import me.stone.stanimeclient.core.ui.databinding.ItemFanGridBinding
import me.stone.stanimeclient.core.ui.databinding.ItemFanLineBinding
import me.stone.stanimeclient.core.ui.extensions.getPositionTag
import me.stone.stanimeclient.core.ui.extensions.setPositionTag
import java.lang.ref.SoftReference
import kotlin.math.ceil
import kotlin.math.roundToInt

class FanSimpleListAdapter
    : PagingDataAdapter<FanSimpleItem, ViewBindingWrapperHolder>(DIFF_CALLBACK),
    View.OnClickListener {

    companion object {
        @JvmStatic
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<FanSimpleItem>() {
            override fun areItemsTheSame(oldItem: FanSimpleItem, newItem: FanSimpleItem): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(
                oldItem: FanSimpleItem,
                newItem: FanSimpleItem
            ): Boolean {
                return oldItem == newItem
            }
        }

        private var itemDecoration: ItemDecoration? = null
    }

    private enum class ViewType {
        GRID {
            override fun createViewBinding(parent: ViewGroup) = ItemFanGridBinding.inflate(
                LayoutInflater.from(parent.context), parent, false
            )

            override fun bindRecyclerView(recyclerView: RecyclerView) {
                recyclerView.layoutManager = GridLayoutManager(recyclerView.context, 3)
                itemDecoration?.let { recyclerView.removeItemDecoration(it) }
            }

            override fun bindData(
                holder: ViewBindingWrapperHolder,
                position: Int,
                item: FanSimpleItem
            ) {
                (holder.binding as? ItemFanGridBinding)?.let {
                    it.item = item
                    it.executePendingBindings()
                }
            }
        },

        LINE {
            override fun createViewBinding(parent: ViewGroup) = ItemFanLineBinding.inflate(
                LayoutInflater.from(parent.context), parent, false
            )

            override fun bindRecyclerView(recyclerView: RecyclerView) {
                recyclerView.layoutManager = LinearLayoutManager(recyclerView.context).apply {
                    orientation = LinearLayoutManager.VERTICAL
                }
                itemDecoration?.let { recyclerView.addItemDecoration(it) }
            }

            override fun bindData(
                holder: ViewBindingWrapperHolder,
                position: Int,
                item: FanSimpleItem
            ) {
                (holder.binding as? ItemFanLineBinding)?.let {
                    it.item = item
                    it.executePendingBindings()
                }
            }
        };

        abstract fun createViewBinding(parent: ViewGroup): ViewDataBinding

        abstract fun bindRecyclerView(recyclerView: RecyclerView)

        abstract fun bindData(holder: ViewBindingWrapperHolder, position: Int, item: FanSimpleItem)
    }

    var enableDynamicHeight: Boolean = false

    private var mItemClickListener: OnItemClickListener<FanSimpleItem>? = null

    private var mRecyclerView: SoftReference<RecyclerView>? = null

    private var mViewType = ViewType.GRID
        set(value) {
            if (field == value) return
            field = value
            mRecyclerView?.get()?.let { field.bindRecyclerView(it) }
            if (enableDynamicHeight) { updateRecyclerDynamicHeight() }
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewBindingWrapperHolder {
        return ViewBindingWrapperHolder(mViewType.createViewBinding(parent))
    }

    override fun onBindViewHolder(holder: ViewBindingWrapperHolder, position: Int) {
        getItem(position)?.let {
            mViewType.bindData(holder, position, it)
            holder.binding.root.setPositionTag(position)
            holder.binding.root.setOnClickListener(this)
        }
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        itemDecoration = DividerItemDecoration(recyclerView.context, DividerItemDecoration.VERTICAL)
        mRecyclerView = SoftReference(recyclerView)
        val dp4 = 4f.dip.roundToInt()
        if (recyclerView.itemDecorationCount == 0) {
            recyclerView.addItemDecoration(object : ItemDecoration() {
                override fun getItemOffsets(
                    outRect: Rect,
                    view: View,
                    parent: RecyclerView,
                    state: RecyclerView.State
                ) {
                    outRect.set(dp4, dp4, dp4, dp4)
                }
            })
        }
        if (recyclerView.paddingTop == 0 || recyclerView.paddingStart == 0) {
            recyclerView.setPaddingRelative(dp4, dp4, dp4, dp4)
        }
        recyclerView.setHasFixedSize(true)
        mViewType.bindRecyclerView(recyclerView)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        mRecyclerView?.clear()
        mRecyclerView = null
    }

    fun updateRecyclerDynamicHeight() {
        val recyclerView = mRecyclerView?.get() ?: return
        val layoutManger = recyclerView.layoutManager as? LinearLayoutManager ?: return
        recyclerView.post {
            val itemView = layoutManger.findViewByPosition(
                layoutManger.findLastVisibleItemPosition()
            ) ?: return@post

            val lines = if (layoutManger is GridLayoutManager) {
                ceil(itemCount.toFloat() / 3).toInt().coerceAtMost(2)
            } else {
                itemCount.coerceAtMost(8)
            }
            val dividerHeight = if (layoutManger !is GridLayoutManager) {
                1f.dip * (lines - 1)
            } else 0f

            val padding = 8f.dip
            val dynamicHeight = ((itemView.height + padding) * lines + padding + dividerHeight)
            recyclerView.layoutParams.height = dynamicHeight.roundToInt()
            recyclerView.post {
                recyclerView.invalidate()
                recyclerView.requestLayout()
            }
        }
    }

    fun toGridStyle() {
        mViewType = ViewType.GRID
    }

    fun toLineStyle() {
        mViewType = ViewType.LINE
    }

    fun setOnItemClickListener(listener: OnItemClickListener<FanSimpleItem>) {
        mItemClickListener = listener
    }

    override fun onClick(v: View) {
        val position = v.getPositionTag().takeIf { it != -1 } ?: return
        getItem(position)?.let { mItemClickListener?.onItemClicked(it) }
    }

}